+function () {
    'use strict';
    function Zooming() {
        this._scaleBase = 1.0;
        this._target = null; // Zoomable target
        this._body = document.body;
        this._lastScrollPosition = null;
        this._scrollThreshold = 40;
        this._handleClick = this._handleClick.bind(this);
        this._handleKeyDown = this._handleKeyDown.bind(this);
        this._handleScroll = this._handleScroll.bind(this);
    }
    Zooming.prototype = {
        init: function () {
            this._body.addEventListener('click', this._handleClick);
            var zoomableImages = document.querySelectorAll('img[data-action="zoom"]');
            for (var i = 0; i < zoomableImages.length; i++) {
                setCursorStyle(zoomableImages[i], 'zoom-in');
            }
        },
        _handleClick: function (event) {
            var target = event.target;
            if (!target)
                return;
            if (target.tagName !== 'IMG')
                this._close();
            if (!target.hasAttribute('data-action'))
                return;
            switch (target.getAttribute('data-action')) {
                case 'zoom':
                    this._zoom(target);
                    break;
                case 'close':
                    this._close();
                    break;
                default:
                    break;
            }
        },
        _handleKeyDown: function (event) {
            if (event.keyCode === 27)
                this._close(); // Esc
        },
        _handleScroll: function () {
            var scrollTop = window.pageYOffset || (document.documentElement || this._body.parentNode || this._body).scrollTop;
            if (this._lastScrollPosition === null)
                this._lastScrollPosition = scrollTop;
            var deltaY = this._lastScrollPosition - scrollTop;
            if (Math.abs(deltaY) >= this._scrollThreshold) {
                this._lastScrollPosition = null;
                this._close();
            }
        },
        _zoom: function (target) {
            // Avoid zooming multiple times
            if (this._target)
                return;
            this._target = new Zoomable(target);
            this._target.zoomIn();
            document.addEventListener('keydown', this._handleKeyDown);
            document.addEventListener('scroll', this._handleScroll);
        },
        _close: function () {
            if (!this._target)
                return;
            this._target.zoomOut();
            this._target = null;
            document.removeEventListener('keydown', this._handleKeyDown);
            document.removeEventListener('scroll', this._handleScroll);
        }
    };
    /**
     * The zoomable image.
     */
    function Zoomable(img) {
        this._scaleBase = 1.0;
        this._image = img;
        this._src = img.getAttribute('src');
        this._dataOriginal = img.getAttribute('data-original');
        this._overlay = null; // An overlay that whites out the body
        this._body = document.body;
        this._zoomImage = this._zoomImage.bind(this);
        this._handleTransitionEnd = this._handleTransitionEnd.bind(this);
        this._styles = {
            image: {
                width: '',
                height: '',
                transform: '',
                zoomIn: {
                    'position': 'relative',
                    'z-index': 666,
                    '-webkit-transition': 'all 300ms',
                    '-o-transition': 'all 300ms',
                    'transition': 'all 300ms'
                },
                zoomOut: {
                    'position': '',
                    'z-index': '',
                    '-webkit-transition': '',
                    '-o-transition': '',
                    'transition': ''
                }
            },
            overlay: {
                'z-index': 233,
                'background': '#fff',
                'position': 'fixed',
                'top': 0,
                'left': 0,
                'right': 0,
                'bottom': 0,
                'filter': 'alpha(opacity=0)',
                'opacity': 0,
                '-webkit-transition': 'opacity 300ms',
                '-o-transition': 'opacity 300ms',
                'transition': 'opacity 300ms'
            }
        };
    }
    Zoomable.prototype = {
        zoomIn: function () {
            var img = new Image();
            img.onload = (function () {
                // If data-orginal is present, set image css width and height explicitly
                // so the transformed source image is correctly displayed
                if (this._dataOriginal) {
                    // Save the original image width and height styles if present
                    this._styles.image.width = this._image.style.width;
                    this._styles.image.height = this._image.style.height;
                    var rect = this._image.getBoundingClientRect();
                    setStyles(this._image, {
                        'width': rect.width + 'px',
                        'height': rect.height + 'px'
                    });
                    // Use data-original as image src
                    this._image.setAttribute('src', this._dataOriginal);
                }
                this._calculateZoom();
                this._zoomImage();
            }).bind(this);
            img.src = this._src;
        },
        _calculateZoom: function () {
            var rect = this._image.getBoundingClientRect();
            var windowCenter = {
                x: window.innerWidth / 2,
                y: window.innerHeight / 2
            };
            var imgHalfWidth = rect.width / 2;
            var imgHalfHeight = rect.height / 2;
            var imgCenter = {
                x: rect.left + imgHalfWidth,
                y: rect.top + imgHalfHeight
            };
            // The vector to translate image to the window center
            var translate = {
                x: windowCenter.x - imgCenter.x,
                y: windowCenter.y - imgCenter.y
            };
            // The distance between image edge and window edge
            var distFromImageEdgeToWindowEdge = {
                x: windowCenter.x - imgHalfWidth,
                y: windowCenter.y - imgHalfHeight
            };
            // The additional scale is based on the smaller value of
            // scaling horizontally and scaling vertically
            var scaleHorizontally = distFromImageEdgeToWindowEdge.x / imgHalfWidth;
            var scaleVertically = distFromImageEdgeToWindowEdge.y / imgHalfHeight;
            var scale = this._scaleBase + Math.min(scaleHorizontally, scaleVertically);
            // Translate the image to window center, then scale the image
            this._styles.image.transform = 'translate(' + translate.x + 'px,' + translate.y + 'px) ' + 'scale(' + scale + ',' + scale + ')';
        },
        _zoomImage: function () {
            // Repaint before animating, fix Safari image flickring issue
            this._image.offsetWidth;
            setStyles(this._image, this._styles.image.zoomIn);
            this._image.addEventListener('transitionend', this._handleTransitionEnd);
            // Create an overlay, it does not white out at this point
            this._overlay = document.createElement('div');
            setStyles(this._overlay, this._styles.overlay);
            this._body.appendChild(this._overlay);
            // Use setTimeout to apply correct overlay opacity transition when
            // zooming in, otherwise the transition effect won't trigger.
            window.setTimeout((function () {
                // Now whites out the overlay
                setStyles(this._overlay, {
                    'filter': "alpha(opacity=100)",
                    'opacity': 1
                });
            }).bind(this), 30);
            this._transform();
        },
        zoomOut: function () {
            this._image.addEventListener('transitionend', this._handleTransitionEnd);
            // Remove the overlay
            setStyles(this._overlay, {
                'filter': "alpha(opacity=0)",
                'opacity': 0
            });
            this._styles.image.transform = '';
            this._transform();
        },
        _transform: function () {
            setStyles(this._image, {
                '-webkit-transform': this._styles.image.transform,
                '-ms-transform': this._styles.image.transform,
                'transform': this._styles.image.transform
            });
        },
        _handleTransitionEnd: function (event) {
            switch (this._image.getAttribute('data-action')) {
                case 'close':
                    if (this._dataOriginal) {
                        setStyles(this._image, {
                            'width': this._styles.width,
                            'height': this._styles.height
                        });
                        // Restore the old image src
                        this._image.setAttribute('src', this._src);
                    }
                    this._body.removeChild(this._overlay);
                    setStyles(this._image, this._styles.image.zoomOut);
                    setCursorStyle(this._image, 'zoom-in');
                    this._image.setAttribute('data-action', 'zoom');
                    break;
                case 'zoom':
                    setCursorStyle(this._image, 'zoom-out');
                    this._image.setAttribute('data-action', 'close');
                    break;
                default:
                    break;
            }
            this._image.removeEventListener('transitionend', this._handleTransitionEnd);
        }
    };
    function setStyles(element, styles) {
        for (var prop in styles) {
            element.style[prop] = styles[prop];
        }
    }
    function setCursorStyle(element, style) {
        element.style.cursor = style;
        element.style.cursor = '-webkit-' + style;
        element.style.cursor = '-moz-' + style;
    }
    document.addEventListener('DOMContentLoaded', function () {
        new Zooming().init();
    });
}();
